package org.study.redisson.boot.service;

import com.alibaba.fastjson2.JSON;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.study.redisson.boot.model.CityInfo;

import java.util.*;

/**
 * Redis GEO
 *
 * @author doveylovey
 * @email 1135782208@qq.com
 * @date 2021年09月07日
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class GeoServiceImpl implements GeoService {
    private String GEO_KEY = "ah-cities";
    private final RedisTemplate redisTemplate;

    @Override
    public Long saveCityInfoToRedis(Collection<CityInfo> cityInfoList) {
        log.info("start to save city info: {}.", JSON.toJSONString(cityInfoList));
        Set<RedisGeoCommands.GeoLocation<String>> locations = new HashSet<>();
        cityInfoList.forEach(ci -> locations.add(new RedisGeoCommands.GeoLocation<>(ci.getCityName(), new Point(ci.getLongitude(), ci.getLatitude()))));
        log.info("done to save city info.");
        return redisTemplate.opsForGeo().add(GEO_KEY, locations);
    }

    @Override
    public List<Point> getCityPos(String[] cities) {
        List position = redisTemplate.opsForGeo().position(GEO_KEY, cities);
        return position;
    }

    @Override
    public Distance getTwoCityDistance(String city1, String city2, Metric metric) {
        Distance distance = null;
        if (metric == null) {
            distance = redisTemplate.opsForGeo().distance(GEO_KEY, city1, city2);
        } else {
            distance = redisTemplate.opsForGeo().distance(GEO_KEY, city1, city2, metric);
        }
        return distance;
    }

    @Override
    public GeoResults<RedisGeoCommands.GeoLocation<String>> getPointRadius(Circle within, RedisGeoCommands.GeoRadiusCommandArgs args) {
        GeoResults radius = null;
        if (args == null) {
            radius = redisTemplate.opsForGeo().radius(GEO_KEY, within);
        } else {
            radius = redisTemplate.opsForGeo().radius(GEO_KEY, within, args);
        }
        return radius;
    }

    @Override
    public GeoResults<RedisGeoCommands.GeoLocation<String>> getMemberRadius(String member, Distance distance, RedisGeoCommands.GeoRadiusCommandArgs args) {
        GeoResults radius = null;
        if (args == null) {
            radius = redisTemplate.opsForGeo().radius(GEO_KEY, member, distance);
        } else {
            radius = redisTemplate.opsForGeo().radius(GEO_KEY, member, distance, args);
        }
        return radius;
    }

    @Override
    public List<String> getCityGeoHash(String[] cities) {
        List<String> hash = redisTemplate.opsForGeo().hash(GEO_KEY, cities);
        return hash;
    }
}
